﻿using Actor.Net.Message;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Text;

namespace Actor.Net.Location
{
    /// <summary>
    /// Key生成器
    /// </summary>
    public static class KeyGenerator
    {
        private static ConcurrentDictionary<string, ConcurrentDictionary<int, string>> HostKeyCache { get; } = new ConcurrentDictionary<string, ConcurrentDictionary<int, string>>();
        private static ConcurrentDictionary<string, ConcurrentDictionary<string, ConcurrentDictionary<string, string>>> ActorKeyCache { get;} = new ConcurrentDictionary<string, ConcurrentDictionary<string, ConcurrentDictionary<string, string>>>();
        private static ConcurrentDictionary<string, ConcurrentDictionary<string, string>> ActorTypeKeyCache { get; } = new ConcurrentDictionary<string, ConcurrentDictionary<string, string>>();
        private static ConcurrentDictionary<string, ConcurrentDictionary<string, ConcurrentDictionary<int, string>>> ServerGroupKeyCache { get; } = new ConcurrentDictionary<string, ConcurrentDictionary<string, ConcurrentDictionary<int, string>>>();
        private static ConcurrentDictionary<string, ConcurrentDictionary<string, ConcurrentDictionary<string, string>>> ActorRouterKeyCache { get; } = new ConcurrentDictionary<string, ConcurrentDictionary<string, ConcurrentDictionary<string, string>>>();

        /// <summary>
        /// 创建Actor服务分组唯一Key
        /// </summary>
        /// <param name="groupInfo"></param>
        /// <returns></returns>
        public static string CreateServerGroupKey(GroupInfo groupInfo)
        {
            return CreateServerGroupKey(groupInfo.ServerGroup, groupInfo.IpAddress, groupInfo.Port);
        }

        /// <summary>
        /// 创建Actor服务分组唯一Key
        /// </summary>
        /// <param name="serverGroup"></param>
        /// <param name="ipAddress"></param>
        /// <param name="port"></param>
        /// <returns></returns>
        public static string CreateServerGroupKey(string serverGroup, string ipAddress, int port)
        {
            if(!ServerGroupKeyCache.TryGetValue(serverGroup, out ConcurrentDictionary<string, ConcurrentDictionary<int, string>> enpointKeyCache))
            {
                enpointKeyCache = new ConcurrentDictionary<string, ConcurrentDictionary<int, string>>();
                ServerGroupKeyCache.AddOrUpdate(serverGroup, enpointKeyCache, (k, v) => enpointKeyCache);
            }

            if(!enpointKeyCache.TryGetValue(ipAddress, out ConcurrentDictionary<int, string> portKeys))
            {
                portKeys = new ConcurrentDictionary<int, string>();
                enpointKeyCache.AddOrUpdate(ipAddress, portKeys, (k, v) => portKeys);
            }

            if(!portKeys.TryGetValue(port, out string key))
            {
                key = $"{serverGroup}:{ipAddress}:{port}";
                portKeys.AddOrUpdate(port, key, (k, v) => key);
            }
            return key;
        }

        /// <summary>
        /// 创建服务主机Key
        /// </summary>
        /// <param name="groupInfo"></param>
        /// <returns></returns>
        public static string CreateHostKey(GroupInfo groupInfo)
        {
            return CreateHostKey(groupInfo.IpAddress, groupInfo.Port);
        }

        /// <summary>
        /// 创建服务主机Key
        /// </summary>
        /// <param name="locationInfo"></param>
        /// <returns></returns>
        public static string CreateHostKey(ActorLocationInfo locationInfo)
        {
            return CreateHostKey(locationInfo.IpAddress, locationInfo.Port);
        }

        /// <summary>
        /// 创建服务主机Key
        /// </summary>
        /// <param name="ipAddress"></param>
        /// <param name="port"></param>
        /// <returns></returns>
        public static string CreateHostKey(string ipAddress, int port)
        {
            if (!HostKeyCache.TryGetValue(ipAddress, out ConcurrentDictionary<int, string> keys))
            {
                keys = new ConcurrentDictionary<int, string>();
                HostKeyCache.AddOrUpdate(ipAddress, keys, (k, v) => keys);
            }

            if(!keys.TryGetValue(port, out string key))
            {
                key = $"{ipAddress}:{port}";
                keys.AddOrUpdate(port, key, (k, v) => key);
            }
            return key;
        }

        /// <summary>
        /// 创建Actor唯一Key
        /// </summary>
        /// <param name="locationInfo"></param>
        /// <returns></returns>
        public static string CreateActorKey(ActorLocationInfo locationInfo)
        {
            return CreateActorKey(locationInfo.ServerGroup, locationInfo.ActorType, locationInfo.ActorId);
        }

        /// <summary>
        /// 创建Actor唯一Key
        /// </summary>
        /// <param name="serverGroup"></param>
        /// <param name="actorType"></param>
        /// <param name="actorId"></param>
        /// <returns></returns>
        public static string CreateActorKey(string serverGroup, string actorType, string actorId)
        {
            if(!ActorKeyCache.TryGetValue(serverGroup, out ConcurrentDictionary<string, ConcurrentDictionary<string, string>> groupCache))
            {
                groupCache = new ConcurrentDictionary<string, ConcurrentDictionary<string, string>>();
                ActorKeyCache.AddOrUpdate(serverGroup, groupCache, (k, v) => groupCache);
            }

            if(!groupCache.TryGetValue(actorType, out ConcurrentDictionary<string, string> typeCache))
            {
                typeCache = new ConcurrentDictionary<string, string>();
                groupCache.AddOrUpdate(actorType, typeCache, (k, v) => typeCache);
            }

            if(!typeCache.TryGetValue(actorId, out string key))
            {
                key = $"{serverGroup}-{actorType}-{actorId}";
                typeCache.AddOrUpdate(actorId, key, (k, v) => key);
            }
            return key;
        }

        /// <summary>
        /// 创建Actor类型唯一Key
        /// </summary>
        /// <param name="locationInfo"></param>
        /// <returns></returns>
        public static string CreateActorTypeKey(ActorLocationInfo locationInfo)
        {
            return CreateActorTypeKey(locationInfo.ServerGroup, locationInfo.ActorType);
        }

        /// <summary>
        /// 创建Actor类型唯一Key
        /// </summary>
        /// <param name="serverGroup"></param>
        /// <param name="actorType"></param>
        /// <returns></returns>
        public static string CreateActorTypeKey(string serverGroup, string actorType)
        {
            if(!ActorTypeKeyCache.TryGetValue(serverGroup, out ConcurrentDictionary<string, string> groupCache))
            {
                groupCache = new ConcurrentDictionary<string, string>();
                ActorTypeKeyCache.AddOrUpdate(serverGroup, groupCache, (k, v) =>groupCache);
            }

            if(!groupCache.TryGetValue(actorType, out string key))
            {
                key = $"{serverGroup}-{actorType}";
                groupCache.AddOrUpdate(actorType, key, (k, v) => key);
            }
            return key;
        }

        /// <summary>
        /// 创建Actor路由唯一Key
        /// </summary>
        /// <param name="serverGroup"></param>
        /// <param name="actorType"></param>
        /// <param name="router"></param>
        /// <returns></returns>
        public static string CreateActorRouterKey(string serverGroup, string actorType, string router)
        {
            if(!ActorRouterKeyCache.TryGetValue(serverGroup, out ConcurrentDictionary<string, ConcurrentDictionary<string, string>> groupCache))
            {
                groupCache = new ConcurrentDictionary<string, ConcurrentDictionary<string, string>>();
                ActorRouterKeyCache.AddOrUpdate(serverGroup, groupCache, (k, v) => groupCache);
            }

            if(!groupCache.TryGetValue(actorType, out ConcurrentDictionary<string, string> typeCache))
            {
                typeCache = new ConcurrentDictionary<string, string>();
                groupCache.AddOrUpdate(actorType, typeCache, (k, v) => typeCache);
            }

            if(!typeCache.TryGetValue(router, out string key))
            {
                key = $"{serverGroup}-{actorType}-{router}";
                typeCache.AddOrUpdate(router, key, (k, v) => key);
            }
            return key;
        }

        /// <summary>
        /// 清空所有的Actor Key
        /// </summary>
        public static void Clear()
        {
            HostKeyCache.Clear();
            ActorKeyCache.Clear();
            ActorTypeKeyCache.Clear();
            ServerGroupKeyCache.Clear();
            ActorRouterKeyCache.Clear();
        }
    }
}
